用户定义类型

  C++解决这个问题的方式就是允许用户直接定义类型,这种类型的行为方式(几乎)与内部类型完全一样。这样的类型常常被称做抽象数据类型,而我更喜欢术语用户定义类型。有关抽象数据类型的一个更合理的定义应当要求一个数学的“抽象”描述。给出了一个这样的描述之后,我们这里所谓的类型就是那种真正抽象实例的一个具体实例。现在程序设计范型变成了:

    确定你需要哪些类型;为每个类型提供完整的一组操作。

在那些对于每个类型都只需要一个对象的地方,采用模块方式实现数据隐藏风格的程序设计也就足够了。

各种算术类型,例如有理数或复数,是用户定义类型的最常见实例。例如,

    class complex
    {
        double re, im;
    public:
        // 从两个标量构造一个复数
        complex(double r, double i) { re = r; im = i; }
        complex(double r) { re = r; im = 0; }
        complex() { re = im = 0; }

        friend complex operator+(complex, complex);
        friend complex operator-(complex, complex);    // 二元
        friend complex operator-(complex);             // 一元
        friend complex operator*(complex, complex);
        friend complex operator/(complex, complex);

        friend bool operator==(complex, complex);      // 等于
        friend bool operator!=(complex, complex);      // 不等于
        // ...     
    };

(也就是用户定义类型)complex的声明描述了一个复数的表示,以及一组对复数的操作。这个表示是私用的,也就是说,reim 只能由类complex的声明里描述的那些函数访问。有关的函数可以按如下方式定义:

    complex operator+(complex a1, complex a2)
    {
        return complex(a1.re + a2,re, a1.im + a2.im);
    }

名字与类名相同的成员函数被称为构造函数。每个构造函数定义了一种初始化这个类的对象的方式。类complex提供了三个构造函数,其中一个从一个double做出了一个complex,另一个从一对double做出一个complex,第三个做出一个具有默认值的complex。

类complex可以按如下方式使用:

    void f(complex z)
    {
        complex a = 2.3;
        complex b = 1/a;
        complex c = a + b * complex(1, 2.3);
        // ...
        if(c != b) c = -(b / a) + 2 * b;
    }

编译器将把涉及到complex数的各种运算转变为适当的函数调用。例如,c != b 的意思是 operator !=(c, b),而 1/a 的意思是operator/(complex(1), a)。

大部分(但并不是全部)模块表示为用户定义类型更好一些。

🔚